package Client;

import java.awt.EventQueue;
import java.awt.Point;
import java.awt.Rectangle;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.ConnectException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

import javax.swing.JDialog;

import chartor.Bullet;
import chartor.Monster;
import chartor.Plas;
import chartor.Player;
import chartor.SmallBlack;
import chartor.SmallBule;
import chartor.SmallGreen;
import chartor.Smallred;
import chartor.infoNumber;
import frame.FindPassword;
import frame.GamePanel;
import frame.Login;
import frame.Match;
import frame.Register;
import frame.myFrame;
import opt.Msg;
import opt.Opertor;

import java.util.Properties;
import java.util.Random;

public class MyClient {
	private ByteBuffer byteBuffer = ByteBuffer.allocate(1024);// 缓冲区
	private ByteBuffer readBuffer = ByteBuffer.allocate(1024);// 读取缓存区
	private Selector selector = null;// 选择器
	private String portString;
	private String urlString;
	private ScheduledThreadPoolExecutor timer = new ScheduledThreadPoolExecutor(2);
	private SocketChannel socketChannel = null;
	private GamePanel pGamePanel;
	private myFrame myFrame;
	private String playerString;
	private int fRame = -1;
	private Login dialog;
	private Register register;
	private int num = 0;// 第几回合
	private FindPassword findpass;
	private Match _matchMatch;// 匹配窗口

	/**
	 * 
	 * 启动通道和selector
	 * 
	 * @throws IOException
	 * 
	 */
	public void setPlayerString(String a) {
		this.playerString = a;
	}

	public int getNum() {
		return this.num;
	}

	public void start() throws IOException {
		// 读取配置信息
		Properties properties = new Properties();
		InputStream iStream = new FileInputStream("Client.properties");
		properties.load(iStream);
		portString = properties.getProperty("port");
		urlString = properties.getProperty("url");
		try {
			socketChannel = SocketChannel.open(new InetSocketAddress(urlString, Integer.parseInt(portString)));
			socketChannel.configureBlocking(false);
		} catch (ConnectException e) {
			System.out.println("连接数据库失败，请检测数据库连接\n");
			return;
		}
		selector = Selector.open();
		socketChannel.register(selector, SelectionKey.OP_READ);
		// 开启线程，接受消息
		receiveMsgThread();
		System.out.println("客户端已经启动");
		// 发送登录请求
		try {
			org.jb2011.lnf.beautyeye.BeautyEyeLNFHelper.launchBeautyEyeLNF();
			dialog = new Login(this);
			dialog.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
			dialog.setVisible(true);
		} catch (Exception e) {
		}
		// 主线程发送消息
	}

	/**
	 * 
	 * 封装对象
	 * 
	 * 
	 * 
	 * 
	 */

	public MyClient() {
		super();
	}

	/**
	 * 
	 * 接受消息
	 * 
	 * @param socketChannel
	 * 
	 * @return
	 * 
	 * @throws IOException
	 * 
	 */
	private Msg readMessage(SocketChannel socketChannel) throws IOException {
		readBuffer.clear();
		Msg msg = null;
		while ((socketChannel.read(readBuffer)) > 0) {
			readBuffer.flip();
			try {
				int len = readBuffer.limit() - readBuffer.position();
				byte[] bytes1 = new byte[len];
				readBuffer.get(bytes1);
				msg = (Msg) Opertor.ByteToObject(bytes1);
			} catch (Exception e) {
				System.out.println("数据转换失败");
				return null;
			}
		}
		return msg;
	}

	/**
	 * 向服务端发送登录请求
	 */
	public void Login(String name, String password) {
		Msg msg = new Msg(-1, "V_LOGIN " + name + " " + password);
		try {
			writeMesage(msg, socketChannel);
		} catch (IOException e) {
		}
	}

	/**
	 * 查找重置密码问题
	 * 
	 * @throws IOException
	 */
	public void FindQuestion(String usernameString, FindPassword findPassword) throws IOException {
		this.findpass = findPassword;
		Msg msg = new Msg(-1, "Query " + usernameString);
		writeMesage(msg, socketChannel);
	}

	/**
	 * 向服务器发送注册请求
	 */
	public void register(String name, String password, Register r, String q, String ans) {
		this.register = r;
		Msg msg = new Msg(-1, "V_register " + name + " " + password + " " + q + " " + ans);
		try {
			writeMesage(msg, socketChannel);
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	/**
	 * 
	 * 发送消息
	 * 
	 * @param str
	 * 
	 * @param socketChannel
	 * 
	 * @throws IOException
	 * 
	 */
	private void writeMesage(Msg msg, SocketChannel socketChannel) throws IOException {
		byteBuffer.clear();
		byteBuffer.put(Opertor.ObjectToByte(msg));
		byteBuffer.flip();
		socketChannel.write(byteBuffer);
	}

	/**
	 * 发送ok信息向服务器
	 *
	 */
	public void putOK() {
		Msg msg = new Msg(-1, "OK");
		try {
			writeMesage(msg, socketChannel);
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	/**
	 * 
	 * 接收消息的线程
	 * 
	 */
	private void receiveMsgThread() {
		new Thread(() -> {
			SocketChannel socketChannel = null;
			while (true) {
				try {
					selector.select();
					Iterator<SelectionKey> iterator = selector.selectedKeys().iterator();
					while (iterator.hasNext()) {
						SelectionKey selectionKey = iterator.next();
						iterator.remove();
						if (selectionKey.isReadable()) {
							socketChannel = (SocketChannel) selectionKey.channel();
							Msg msgReciv = readMessage(socketChannel);
							handleMsg(msgReciv);
						}
					}
					selector.selectedKeys().clear();
				} catch (IOException e) {
					if (socketChannel != null) {
						try {
							socketChannel.close();
						} catch (IOException ex) {
							ex.printStackTrace();
						}
					}
				}
			}
		}).start();
	}

	/**
	 * 
	 * 收到信息后处理
	 * 
	 * @param args
	 * 
	 * @throws IOException
	 * 
	 */
	public void handleMsg(Msg msg) throws IOException {
		if (msg == null)
			return;
		if (msg.getFrame() >= 0) {
			fRame++;
			for (Monster m : Plas.monsters) {
				m.mont();
			}
			for (Bullet s : Plas.bullets) {
				s.mont();
			}
			// System.out.println(msg);
			Iterator<String> iterator = msg.getList().iterator();
			while (iterator.hasNext()) {
				String s[] = iterator.next().split(" ");
				if (s[0].equals("birth")) {
					Plas.birth(Plas.random.nextInt(800) + 100, Plas.random.nextInt(800) + 100, false, false, false,
							false, s[1]);
					if (s[1].equals(playerString)) {
						pGamePanel.setPlayerman(Plas.players.get(playerString));
						Plas.playermanPlayer = Plas.players.get(playerString);
						readClient();
						Action();
						pGamePanel.revalidate();
						birthMonster();
						long l = Runtime.getRuntime().totalMemory();
						System.out.println("总共的内存是" + l + "字节\t" + l / (double) 1024 / 1024 + "MB");
					}
				} else if (s[0].equals("M")) {
					if (s[2].equals("a")) {
						Plas.players.get(s[1]).adnum(0);
					} else if (s[2].equals("s")) {
						Plas.players.get(s[1]).adnum(1);
					} else if (s[2].equals("d")) {
						Plas.players.get(s[1]).adnum(2);
					} else if (s[2].equals("w")) {
						Plas.players.get(s[1]).adnum(3);
					} else if (s[2].equals("aS")) {
						Plas.players.get(s[1]).adnum(4);
					} else if (s[2].equals("sS")) {
						Plas.players.get(s[1]).adnum(5);
					} else if (s[2].equals("dS")) {
						Plas.players.get(s[1]).adnum(6);
					} else if (s[2].equals("wS")) {
						Plas.players.get(s[1]).adnum(7);
					}
				} else if (s[0].equals("S") && s.length >= 5) {
					int state = Integer.parseInt(s[4]);
					int x = Integer.parseInt(s[2]);
					int y = Integer.parseInt(s[3]);
					Plas.players.get(s[1]).tututu(state, new Point(x, y));
				} else if (s[0].equals("R")) {
					Plas.players.get(s[1]).getClasses().reload();
				} else if (s[0].equals("Q")) {
					int x = Integer.parseInt(s[2]);
					Plas.players.get(s[1]).setClasses(Plas.players.get(s[1]).getGuns().get(x));
				} else if (s[0].equals("death")) {
					Plas.players.get(s[1]).setHealth(0);
					Plas.players.get(s[1]).setGotnumer(Integer.parseInt(s[2]));
				}
			}
		} else {
			String[] arr = msg.getList().get(0).split(" ");
			if (arr[0].equals("V_BeginGame")) {
				// 确认随机数
				System.out.println("随机数为：" + arr[1]);
				Plas.random = new Random(Integer.parseInt(arr[1]));
				pGamePanel = new GamePanel(this);
				myFrame.setContentPane(pGamePanel);
				pGamePanel.requestFocus();
			} else if (arr[0].equals("LOGINED")) {
				dialog.isLogin(true);
				// 启动一些窗体事件
				createGameframe(this);
			} else if (arr[0].equals("LOGINEDFAIL")) {
				dialog.isLogin(false);
			} else if (arr[0].equals("registered")) {
				register.isRegister(true);
			} else if (arr[0].equals("registerFAIL")) {
				register.isRegister(false);
			} else if (arr[0].equals("bMonster")) {
				Plas.random = new Random(Integer.parseInt(arr[1]));
				for (int i = 0; i < num % 20; i++) {
					Plas.monsters.add(new Smallred(Plas.random.nextInt(3000), Plas.random.nextInt(3000)));
				}
				for (int i = 0; i < num / 5; i++) {
					Plas.monsters.add(new SmallGreen(Plas.random.nextInt(3000), Plas.random.nextInt(3000)));
				}
				for (int i = 0; i < num / 3; i++)
					Plas.monsters.add(new SmallBlack(Plas.random.nextInt(3000), Plas.random.nextInt(3000)));
				for (int i = 0; i < num / 10; i++)
					Plas.monsters.add(new SmallBule(Plas.random.nextInt(3000), Plas.random.nextInt(3000)));
				num++;
			} else if (arr[0].equals("UserQuestion")) {
				findpass.setQuestion(arr[1]);
				findpass.setAnswringString(arr[2]);
			} else if (arr[0].equals("update_success")) {
				findpass.isReset(true);
			} else if (arr[0].equals("update_fail")) {
				findpass.isReset(false);
			}
		}
	}

	/**
	 * 创建游戏窗口
	 * 
	 * @param myClient
	 */
	public void createGameframe(MyClient myClient) {
		EventQueue.invokeLater(new Runnable() {
			public void run() {
				try {
					myFrame = new myFrame();
					myFrame.setVisible(true);
					_matchMatch = new Match(myClient);
					myFrame.setContentPane(_matchMatch);
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		});
	}

	/**
	 * 重置密码
	 */
	public void ResetPassword(String usernameString, String passwordString) {
		Msg msg = new Msg(-1, "update " + usernameString + " " + passwordString);
		try {
			System.out.println("请求更新");
			writeMesage(msg, socketChannel);
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	/**
	 * 向服务器发送匹配请求
	 */
	public void Match() {
		Msg msg = new Msg(-1, "MATCH " + playerString);
		try {
			writeMesage(msg, socketChannel);
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	/**
	 * 开始读取客户端信息
	 * 
	 * @param args
	 * @throws IOException
	 */
	public void readClient() {
		timer.scheduleAtFixedRate(new Runnable() {
			Boolean TTT = true;

			@Override
			public void run() {
				try {
					if (TTT) {
						if (Plas.playermanPlayer.getHealth() <= 0) {
							Msg msg = new Msg(fRame, "death " + Plas.playermanPlayer.getNameString() + " "
									+ Plas.playermanPlayer.getGotnumer());
							writeMesage(msg, socketChannel);
							TTT = false;
							return;
						}
						Msg msg = new Msg();
						msg.setFrame(fRame);
						List<String> comList = new ArrayList<String>();
						if (Plas.playermanPlayer.isA()) {
							String a = "M ".concat(Plas.playermanPlayer.getNameString()).concat(" a");
							if (Plas.playermanPlayer.isShift())
								a = a.concat("S");
							comList.add(a);
						}
						if (Plas.playermanPlayer.isS()) {
							String a = "M ".concat(Plas.playermanPlayer.getNameString()).concat(" s");
							if (Plas.playermanPlayer.isShift())
								a = a.concat("S");
							comList.add(a);
						}

						if (Plas.playermanPlayer.isD()) {
							String a = "M ".concat(Plas.playermanPlayer.getNameString()).concat(" d");
							if (Plas.playermanPlayer.isShift())
								a = a.concat("S");
							comList.add(a);
						}
						if (Plas.playermanPlayer.isW()) {
							String a = "M ".concat(Plas.playermanPlayer.getNameString()).concat(" w");
							if (Plas.playermanPlayer.isShift())
								a = a.concat("S");
							comList.add(a);
						}
						if (Plas.playermanPlayer.isJ()) {
							if (!(Plas.playermanPlayer.getClasses().jindutiao != null
									&& Plas.playermanPlayer.getClasses().jindutiao.isOk())
									&& Plas.playermanPlayer.getClasses().getCool()) {
								String a = "S ".concat(Plas.playermanPlayer.getNameString() + " ");
								a = a.concat((Plas.playermanPlayer.targetpoint_x) + " "
										+ (Plas.playermanPlayer.targetpoint_y));
								int state = 1;
								if (Plas.playermanPlayer.isA() || Plas.playermanPlayer.isS()
										|| Plas.playermanPlayer.isD() || Plas.playermanPlayer.isW()) {
									state++;
									if (Plas.playermanPlayer.isShift())
										state++;
								}
								a = a.concat(" " + state);
								comList.add(a);
							}
						}
						if (Plas.playermanPlayer.isR()) {
							String a = "R ".concat(Plas.playermanPlayer.getNameString());
							comList.add(a);
						}
						if (Plas.playermanPlayer.isNum1()) {
							String a = "Q ".concat(Plas.playermanPlayer.getNameString() + " 0");
							comList.add(a);
						}
						if (Plas.playermanPlayer.isNum2()) {
							String a = "Q ".concat(Plas.playermanPlayer.getNameString() + " 1");
							comList.add(a);
						}
						if (Plas.playermanPlayer.isNum3()) {
							String a = "Q ".concat(Plas.playermanPlayer.getNameString() + " 2");
							comList.add(a);
						}
						msg.setList(comList);
						writeMesage(msg, socketChannel);
					}
				} catch (Exception e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
		}, 0, 66, TimeUnit.MILLISECONDS);
	}

	public void Action() {
		// 启动线程 监听操作
		timer.scheduleAtFixedRate(new Runnable() {
			@Override
			public void run() {
				try {
					for (Player s : Plas.players.values()) {
						s.Mont();
						if (s.getClasses().jindutiao != null)
							s.getClasses().jindutiao.move();
					}
					for (Bullet s : Plas.bullets) {
						s.move();
					}
					for (Monster m : Plas.monsters) {
						m.selectman();
						if (m.getuGun() != null && m.getuGun().jindutiao != null) {
							m.getuGun().jindutiao.move();
						}
						m.move();
					}
					penzhuang();
				} catch (Exception e) {
					// TODO: handle exception
					e.printStackTrace();
				}

			}
		}, 0, 16, TimeUnit.MILLISECONDS);
	}

	public void birthMonster() {
		timer.scheduleAtFixedRate(new Runnable() {
			@Override
			public void run() {
				//System.out.println("发送击杀请求" + fRame);
				if (Plas.monsters.size() <= 0) {
					Msg msg = new Msg(-1, "allkill");
					try {
						writeMesage(msg, socketChannel);
					} catch (IOException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
				}
			}
		}, 10000, 1000, TimeUnit.MILLISECONDS);
	}

	public void penzhuang() {
		pGamePanel.quadtree.clear();
		for (Player p : Plas.players.values()) {
			pGamePanel.quadtree.insert(p);
		}
		Iterator<Bullet> iterable = Plas.bullets.iterator();
		while (iterable.hasNext()) {
			Bullet bullet = iterable.next();
			if (!pGamePanel.quadtree.getBunds().contains(bullet)) {
				iterable.remove();
			} else {
				pGamePanel.quadtree.insert(bullet);
			}
		}
		Iterator<Monster> iterable1 = Plas.monsters.iterator();
		synchronized (Plas.monsters) {
			while (iterable1.hasNext()) {
				Monster m = iterable1.next();
				if (m.getHealth() <= 0) {
					iterable1.remove();
				} else
					pGamePanel.quadtree.insert(m);
			}
		}

		iterable = Plas.bullets.iterator();
		while (iterable.hasNext()) {
			Bullet bullet = iterable.next();
			List<Rectangle> list = pGamePanel.quadtree.retrieve(new ArrayList<Rectangle>(), bullet);
			for (Rectangle r : list) {
				if ((r.intersects(bullet) || r.contains(bullet)) && r instanceof Player
						&& !bullet.getShootmanPlayer().equals(r)) {
					Player tPlayer = (Player) r;
					tPlayer.setHealth((tPlayer.getHealth() - bullet.getDamage()));
					Plas.infoNumbers.add(new infoNumber("-" + bullet.getDamage(),
							tPlayer.x - 50 + Plas.random2.nextInt(50), tPlayer.y - 50 + Plas.random2.nextInt(50), 20));
					iterable.remove();
					break;
				} else if ((r.intersects(bullet) || r.contains(bullet)) && r instanceof Monster
						&& !bullet.getShootmanPlayer().equals(r)) {
					Monster monster = (Monster) r;
					if (monster.getHealth() <= 0)
						continue;
					monster.setHealth(monster.getHealth() - bullet.getDamage());
					Plas.infoNumbers.add(new infoNumber("-" + bullet.getDamage(),
							monster.x - 50 + Plas.random2.nextInt(50), monster.y - 50 + Plas.random2.nextInt(50), 20));
					monster.beatk(bullet);
					iterable.remove();
					if (monster.getHealth() <= 0 && bullet.getShootmanPlayer() instanceof Player) {
						Player player = (Player) bullet.getShootmanPlayer();
						player.setGotnumer(player.getGotnumer() + 1);
						monster.reword((Player) bullet.getShootmanPlayer());
					}
					break;
				}
			}
		}
		iterable1 = Plas.monsters.iterator();
		while (iterable1.hasNext()) {
			Monster monster = iterable1.next();
			List<Rectangle> list = pGamePanel.quadtree.retrieve(new ArrayList<Rectangle>(), monster);
			for (Rectangle r : list) {
				if ((r.intersects(monster) || r.contains(monster)) && r instanceof Monster) {
					Monster mtMonster = (Monster) r;
					monster.avoid(mtMonster);
				} else if ((r.intersects(monster) || r.contains(monster)) && r instanceof Player) {
					monster.atkman((Player) r);
					monster.avoid(r);
				}
			}
		}
	}

	public static void main(String[] args) throws IOException {
		new MyClient().start();
	}
}
